{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Wait for User Input"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "String userHomeDir = System.getProperty(\"user.home\");\n",
    "String localRespoUrl = \"file://\" + userHomeDir + \"/.m2/repository/\";\n",
    "String langchain4jVersion = \"0.36.2\";\n",
    "String langgraph4jVersion = \"1.4-SNAPSHOT\";"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mRepository \u001b[1m\u001b[32mlocal\u001b[0m url: \u001b[1m\u001b[32mfile:///Users/bsorrentino/.m2/repository/\u001b[0m added.\n",
      "\u001b[0mAdding dependency \u001b[0m\u001b[1m\u001b[32morg.bsc.langgraph4j:langgraph4j-core:1.3-SNAPSHOT\n",
      "\u001b[0mAdding dependency \u001b[0m\u001b[1m\u001b[32morg.bsc.langgraph4j:langgraph4j-langchain4j:1.3-SNAPSHOT\n",
      "\u001b[0mAdding dependency \u001b[0m\u001b[1m\u001b[32mdev.langchain4j:langchain4j:0.36.2\n",
      "\u001b[0mAdding dependency \u001b[0m\u001b[1m\u001b[32mdev.langchain4j:langchain4j-open-ai:0.36.2\n",
      "\u001b[0mAdding dependency \u001b[0m\u001b[1m\u001b[32mnet.sourceforge.plantuml:plantuml-mit:1.2024.6\n",
      "\u001b[0mProposed dependencies count: 5\n",
      "\u001b[0m - \u001b[1m\u001b[32morg.bsc.langgraph4j:langgraph4j-core:jar:1.3-SNAPSHOT (runtime)\n",
      "\u001b[0m\u001b[0m - \u001b[1m\u001b[32morg.bsc.langgraph4j:langgraph4j-langchain4j:jar:1.3-SNAPSHOT (runtime)\n",
      "\u001b[0m\u001b[0m - \u001b[1m\u001b[32mdev.langchain4j:langchain4j:jar:0.36.2 (runtime)\n",
      "\u001b[0m\u001b[0m - \u001b[1m\u001b[32mdev.langchain4j:langchain4j-open-ai:jar:0.36.2 (runtime)\n",
      "\u001b[0m\u001b[0m - \u001b[1m\u001b[32mnet.sourceforge.plantuml:plantuml-mit:jar:1.2024.6 (runtime)\n",
      "\u001b[0mResolved dependencies count: 0\n",
      "Solving dependencies\n",
      "Resolved artifacts count: 26\n",
      "Add to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/org/bsc/langgraph4j/langgraph4j-core/1.3-SNAPSHOT/langgraph4j-core-1.3-SNAPSHOT.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/org/bsc/async/async-generator/3.0.0/async-generator-3.0.0.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/org/slf4j/slf4j-api/2.0.9/slf4j-api-2.0.9.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/org/bsc/langgraph4j/langgraph4j-langchain4j/1.3-SNAPSHOT/langgraph4j-langchain4j-1.3-SNAPSHOT.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/dev/langchain4j/langchain4j/0.36.2/langchain4j-0.36.2.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/dev/langchain4j/langchain4j-core/0.36.2/langchain4j-core-0.36.2.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/com/google/code/gson/gson/2.10.1/gson-2.10.1.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/org/apache/opennlp/opennlp-tools/1.9.4/opennlp-tools-1.9.4.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/dev/langchain4j/langchain4j-open-ai/0.36.2/langchain4j-open-ai-0.36.2.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/dev/ai4j/openai4j/0.23.0/openai4j-0.23.0.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/com/squareup/retrofit2/retrofit/2.9.0/retrofit-2.9.0.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/com/squareup/retrofit2/converter-jackson/2.9.0/converter-jackson-2.9.0.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/com/fasterxml/jackson/core/jackson-databind/2.17.2/jackson-databind-2.17.2.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/com/fasterxml/jackson/core/jackson-annotations/2.17.2/jackson-annotations-2.17.2.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/com/fasterxml/jackson/core/jackson-core/2.17.2/jackson-core-2.17.2.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/com/squareup/okhttp3/okhttp/4.12.0/okhttp-4.12.0.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/com/squareup/okio/okio/3.6.0/okio-3.6.0.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/com/squareup/okio/okio-jvm/3.6.0/okio-jvm-3.6.0.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/org/jetbrains/kotlin/kotlin-stdlib-common/1.9.10/kotlin-stdlib-common-1.9.10.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/com/squareup/okhttp3/okhttp-sse/4.12.0/okhttp-sse-4.12.0.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.9.25/kotlin-stdlib-jdk8-1.9.25.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/org/jetbrains/kotlin/kotlin-stdlib/1.9.25/kotlin-stdlib-1.9.25.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/org/jetbrains/annotations/13.0/annotations-13.0.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.9.25/kotlin-stdlib-jdk7-1.9.25.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/com/knuddels/jtokkit/1.1.0/jtokkit-1.1.0.jar\u001b[0m\n",
      "\u001b[0mAdd to classpath: \u001b[0m\u001b[32m/Users/bsorrentino/Library/Jupyter/kernels/rapaio-jupyter-kernel/mima_cache/net/sourceforge/plantuml/plantuml-mit/1.2024.6/plantuml-mit-1.2024.6.jar\u001b[0m\n",
      "\u001b[0m"
     ]
    }
   ],
   "source": [
    "%dependency /add-repo local \\{localRespoUrl} release|never snapshot|always\n",
    "// %dependency /list-repos\n",
    "%dependency /add org.bsc.langgraph4j:langgraph4j-core:\\{langgraph4jVersion}\n",
    "%dependency /add org.bsc.langgraph4j:langgraph4j-langchain4j:\\{langgraph4jVersion}\n",
    "%dependency /add dev.langchain4j:langchain4j:\\{langchain4jVersion}\n",
    "%dependency /add dev.langchain4j:langchain4j-open-ai:\\{langchain4jVersion}\n",
    "%dependency /add net.sourceforge.plantuml:plantuml-mit:1.2024.6\n",
    "%dependency /list-dependencies\n",
    "%dependency /resolve"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import net.sourceforge.plantuml.SourceStringReader;\n",
    "import net.sourceforge.plantuml.FileFormatOption;\n",
    "import net.sourceforge.plantuml.FileFormat;\n",
    "\n",
    "static java.awt.Image plantUML2PNG( String code ) throws IOException { \n",
    "    var reader = new SourceStringReader(code);\n",
    "\n",
    "    try(var imageOutStream = new java.io.ByteArrayOutputStream()) {\n",
    "\n",
    "        var description = reader.outputImage( imageOutStream, 0, new FileFormatOption(FileFormat.PNG));\n",
    "\n",
    "        var imageInStream = new java.io.ByteArrayInputStream(  imageOutStream.toByteArray() );\n",
    "\n",
    "        return javax.imageio.ImageIO.read( imageInStream );\n",
    "\n",
    "    }\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "SLF4J: No SLF4J providers were found.\n",
      "SLF4J: Defaulting to no-operation (NOP) logger implementation\n",
      "SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "@startuml Graph_Diagram\n",
       "skinparam usecaseFontSize 14\n",
       "skinparam usecaseStereotypeFontSize 12\n",
       "skinparam hexagonFontSize 14\n",
       "skinparam hexagonStereotypeFontSize 12\n",
       "title \"Graph Diagram\"\n",
       "footer\n",
       "\n",
       "powered by langgraph4j\n",
       "end footer\n",
       "circle start<<input>> as __START__\n",
       "circle stop as __END__\n",
       "usecase \"step_1\"<<Node>>\n",
       "usecase \"human_feedback\"<<Node>>\n",
       "usecase \"step_3\"<<Node>>\n",
       "\"__START__\" -down-> \"step_1\"\n",
       "\"step_1\" -down-> \"human_feedback\"\n",
       "\"human_feedback\" -down-> \"step_3\"\n",
       "\"step_3\" -down-> \"__END__\"\n",
       "@enduml\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "c1ce6176-a34b-4110-953e-0923f3918f51"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import org.bsc.langgraph4j.*;\n",
    "import org.bsc.langgraph4j.prebuilt.MessagesState;\n",
    "import org.bsc.langgraph4j.state.Channel;\n",
    "import org.bsc.langgraph4j.state.AppenderChannel;\n",
    "import dev.langchain4j.data.message.AiMessage;\n",
    "import dev.langchain4j.data.message.ChatMessage;\n",
    "import org.bsc.langgraph4j.action.AsyncNodeAction;\n",
    "import static org.bsc.langgraph4j.action.AsyncNodeAction.node_async;\n",
    "import static org.bsc.langgraph4j.utils.CollectionsUtils.mapOf;\n",
    "import org.bsc.langgraph4j.checkpoint.MemorySaver;\n",
    "import org.bsc.langgraph4j.CompileConfig;\n",
    "import static org.bsc.langgraph4j.StateGraph.END;\n",
    "import static org.bsc.langgraph4j.StateGraph.START;\n",
    "\n",
    "public class State extends MessagesState {\n",
    "\n",
    "    public State(Map<String, Object> initData) {\n",
    "        super( initData  );\n",
    "    }\n",
    "\n",
    "    Optional<String> input() { return value(\"input\"); } \n",
    "    Optional<String> userFeedback() { return value(\"user_feedback\"); } \n",
    "\n",
    "}\n",
    "\n",
    "AsyncNodeAction<State> step1 = node_async(state -> {\n",
    "    System.out.println( \"---Step 1---\" );\n",
    "    return mapOf();\n",
    "});\n",
    "\n",
    "AsyncNodeAction<State> humanFeedback = node_async(state -> {\n",
    "    System.out.println( \"---human_feedback---\" );\n",
    "    return mapOf();\n",
    "});\n",
    "\n",
    "AsyncNodeAction<State> step3 = node_async(state -> {\n",
    "    System.out.println( \"---Step 3---\" );\n",
    "    return mapOf();\n",
    "});\n",
    "\n",
    "var builder = new StateGraph<>(State.SCHEMA, State::new);\n",
    "builder.addNode(\"step_1\", step1);\n",
    "builder.addNode(\"human_feedback\", humanFeedback);\n",
    "builder.addNode(\"step_3\", step3);\n",
    "builder.addEdge(START, \"step_1\");\n",
    "builder.addEdge(\"step_1\", \"human_feedback\");\n",
    "builder.addEdge(\"human_feedback\", \"step_3\");\n",
    "builder.addEdge(\"step_3\", END);\n",
    "\n",
    "// Set up memory\n",
    "var saver = new MemorySaver();\n",
    "\n",
    "// Add\n",
    "var compileConfig = CompileConfig.builder().checkpointSaver(saver).interruptBefore(\"human_feedback\").build();\n",
    "var graph = builder.compile(compileConfig);\n",
    "\n",
    "// View as PlantUML \n",
    "var plantuml = graph.getGraph(GraphRepresentation.Type.PLANTUML).getContent();\n",
    "\n",
    "display( plantuml );\n",
    "display( plantUML2PNG(plantuml) );"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---Step 1---\n",
      "NodeOutput{node=__START__, state={input=hello world, messages=[]}}\n",
      "NodeOutput{node=step_1, state={input=hello world, messages=[]}}\n"
     ]
    }
   ],
   "source": [
    "// Input\n",
    "var initialInput = mapOf(\"input\", (Object) \"hello world\");\n",
    "\n",
    "// Thread\n",
    "var invokeConfig = RunnableConfig.builder().threadId(\"Thread1\").build();\n",
    "\n",
    "// Run the graph until the first interruption\n",
    "for (var event : graph.stream(initialInput, invokeConfig)) {\n",
    "    System.out.println(event);\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tell me how you want to update the state: go to step 3!\n",
      "--State after update--\n",
      "StateSnapshot{node=step_1, state={user_feedback=go to step 3!, input=hello world, messages=[]}, config=RunnableConfig(threadId=Thread1, checkPointId=5a31577e-2b4a-4db8-a969-9a58dae4a080, nextNode=human_feedback, streamMode=VALUES)}\n",
      "getNext with invokeConfig: human_feedback\n",
      "getNext with updateConfig: human_feedback\n"
     ]
    }
   ],
   "source": [
    "// Get user input\n",
    "//String userInput = new Scanner(System.in).nextLine();\n",
    "String userInput = \"go to step 3!\";\n",
    "System.out.println(\"Tell me how you want to update the state: \" + userInput);\n",
    "\n",
    "// We now update the state as if we are the human_feedback node\n",
    "//var updateConfig = graph.updateState(invokeConfig, mapOf(\"user_feedback\", userInput), \"human_feedback\");\n",
    "var updateConfig = graph.updateState(invokeConfig, mapOf(\"user_feedback\", userInput), null);\n",
    "\n",
    "// We can check the state\n",
    "System.out.println(\"--State after update--\");\n",
    "System.out.println(graph.getState(invokeConfig));\n",
    "\n",
    "// We can check the next node, showing that it is node 3 (which follows human_feedback)\n",
    "System.out.println(\"getNext with invokeConfig: \" + graph.getState(invokeConfig).getNext());\n",
    "System.out.println(\"getNext with updateConfig: \" + graph.getState(updateConfig).getNext());"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---human_feedback---\n",
      "---Step 3---\n",
      "NodeOutput{node=human_feedback, state={user_feedback=go to step 3!, input=hello world, messages=[]}}\n",
      "NodeOutput{node=step_3, state={user_feedback=go to step 3!, input=hello world, messages=[]}}\n",
      "NodeOutput{node=__END__, state={user_feedback=go to step 3!, input=hello world, messages=[]}}\n"
     ]
    }
   ],
   "source": [
    "// Continue the graph execution\n",
    "for (var event : graph.stream(null, updateConfig)) {\n",
    "    System.out.println(event);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{user_feedback=go to step 3!, input=hello world, messages=[]}"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.getState(updateConfig).getState();"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Java (rjk 2.2.0)",
   "language": "java",
   "name": "rapaio-jupyter-kernel"
  },
  "language_info": {
   "codemirror_mode": "java",
   "file_extension": ".jshell",
   "mimetype": "text/x-java-source",
   "name": "java",
   "nbconvert_exporter": "script",
   "pygments_lexer": "java",
   "version": "17.0.2+8-86"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
